package com.db.collections.inthashmap;


import com.db.collections.CantFindItemException;

public class IntHashMap implements IntMap{
    private int BUCKET_SIZE = 32;
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    int capacity;
    Entity[] values;
    int size;

    public IntHashMap() {
        values = new Entity[BUCKET_SIZE];
        this.capacity = 100;
        this.size = 0;
    }

    public int put(int k, int v) {
        int bucketNumber = k % BUCKET_SIZE;
        if (values[bucketNumber] == null) {
            size++;
            values[bucketNumber] = new Entity(k, v);
        } else {
            values[k % 16].put(k, v);
        }
        if (size >= capacity * DEFAULT_LOAD_FACTOR) {
            resize();
        }
        return v;
    }

    private void resize() {
        Entity[] oldValues = values;
        values = new Entity[BUCKET_SIZE * 2];
        size = 0;
        BUCKET_SIZE *= 2;
        capacity *= 2;
        for (Entity e : oldValues) {
            while (e != null) {
                put(e.key, e.value);
                e = e.next;
            }
        }
    }

    public int remove(int k) {
        int bucketNumber = k % BUCKET_SIZE;
        if (values[bucketNumber] == null) {
            throw new CantFindItemException();
        } else {
            if (values[bucketNumber].key == k) {
                int value = values[bucketNumber].value;
                values[bucketNumber] = values[bucketNumber].next;
                size--;
                return value;
            } else {
                return values[bucketNumber].remove(k);
            }
        }
    }

    public int get(int k) {
        int bucketNumber = k % BUCKET_SIZE;
        if (values[bucketNumber] == null) {
            throw new CantFindItemException();
        }
        return values[bucketNumber].get(k);
    }

    public boolean contains(int k) {
        int bucketNumber = k % BUCKET_SIZE;
        return values[bucketNumber] != null && values[bucketNumber].contains(k);
    }


    public void clear() {
        this.values = new Entity[BUCKET_SIZE];
    }


    class Entity {
        public final int key;
        public int value;
        Entity next;

        Entity(int key, int value) {
            this.key = key;
            this.value = value;
            this.next = null;
        }

        public void put(int key, int value) {
            if (this.key == key) {
                this.value = value;
            } else {
                if (next != null) {
                    next.put(key, value);
                } else {
                    size++;
                    next = new Entity(key, value);
                }
            }
        }

        public int remove(int k) {
            if (next != null) {
                if (next.key == k) {
                    int value = next.value;
                    next = next.next;
                    size--;
                    return value;
                } else {
                    return next.remove(k);
                }
            } else {
                throw new CantFindItemException();
            }
        }

        public int get(int k) {
            if (k == key) {
                return value;
            } else {
                if (next != null) {
                    return next.get(k);
                } else {
                    throw new CantFindItemException();
                }
            }
        }

        public boolean contains(int k) {
            if (k == key) return true;
            else {
                return next != null && next.contains(k);
            }
        }
    }
}
